amends "../snippetTest.pkl"

local base = new Mapping {
  default {
    name = Undefined()
    age = 42
  }
  ["Pigeon"] {
    name = "Pigeon"
  }
  ["Parrot"] {
    name = "Parrot"
    age = 24
  }
}

local derived = (base) {
  ["Pigeon"] {
    name = "Piggy"
  }
  ["Barn Owl"] {
    name = "Barn Owl"
    age = 84
  }
}

local empty = new Mapping {
  default = (_) -> 1
}

local empty2 = (empty) {
  default = (name) -> name.length + 2
  local `_` = 42
  local function `_`() = 42
}

local typedMapping: Mapping<String, String> = new {
  ["hello"] = "hellooooo"
}

local delegatingTypedMapping: Mapping<String, String|Int> = typedMapping

facts {
  ["isEmpty"] {
    !base.isEmpty
    !derived.isEmpty
    empty.isEmpty
    empty2.isEmpty
  }

  ["containsKey()"] {
    base.containsKey("Pigeon")
    base.containsKey("Parrot")
    !base.containsKey("Barn Owl")
    !base.containsKey("Other")

    derived.containsKey("Pigeon")
    derived.containsKey("Parrot")
    derived.containsKey("Barn Owl")
    !derived.containsKey("Other")

    !empty.containsKey("Pigeon")
    !empty.containsKey("default")
    !empty2.containsKey("Pigeon")

    delegatingTypedMapping.containsKey("hello")
  }

  ["containsValue()"] {
    !empty.containsValue("Any value")
    for (_, v in derived) {
      derived.containsValue(v)
    }
  }

  ["length"] {
    empty.length == 0
    base.length == 2
    derived.length == 3
  }

  ["keys (of type string)"] {
    empty.keys == Set()
    derived.keys == Set("Pigeon", "Parrot", "Barn Owl")
    base.keys == Set("Pigeon", "Parrot")
  }

  ["keys (of type object)"] {
    local base2 = new Mapping {
      [empty] = "one"
      [base] = "two"
    }
    local derived2 = (base2) {
      [derived] = "three"
    }

    base2.keys == Set(empty, base)
    derived2.keys == Set(empty, base, derived)
  }

  ["every()"] {
    empty.every((_, _) -> throw("unreachable code"))
    base.every((k, v) -> k == "Parrot" || v.age > 30)
    !base.every((k, _) -> k == "Pigeon")
  }

  ["any()"] {
    base.any((k, _) -> k.contains("rot"))
    base.any((_, v) -> v.age > 40)
    !base.any((k, _) -> k.contains("other"))
  }
}

examples {
  ["getOrNull()"] {
    base.getOrNull("Pigeon")
    base.getOrNull("Parrot")
    base.getOrNull("Barn Owl")
    base.getOrNull("Other")

    derived.getOrNull("Pigeon")
    derived.getOrNull("Parrot")
    derived.getOrNull("Barn Owl")
    derived.getOrNull("Other")

    empty.getOrNull("Pigeon")
    empty2.getOrNull("Pigeon")
  }

  ["fold()"] {
    base.fold(List(), (l, k, v) -> l.add(Pair(k, v)))
    derived.fold(List(), (l, k, v) -> l.add(Pair(k, v)))
    empty.fold(List(), (l, k, v) -> l.add(Pair(k, v)))
    empty2.fold(List(), (l, k, v) -> l.add(Pair(k, v)))
  }

  ["toMap()"] {
    base.toMap()
    derived.toMap()
    empty.toMap()
    empty2.toMap()
  }
}
